package shapes;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.NoSuchElementException;
import java.util.Scanner;

import javax.swing.*;

import util.RenderMatrix;

/*
 * Notes: For milestone 2 submission 2 I decided to re-write the entire project from the beginning as
 *        the original submission code was a patchwork mess.  Once all the code was written one small bug 
 *        still remained and that was with the frustum and lookat matrices. For some reason matrices were 
 *        producing very wierd results.  That is when my consultant came in an saved the project.  He found 
 *        the bug and fixed it.  Thanks to Dustin the code is completed and passes all the tests. 
 * 
 */

/**
 * 
 * @author Tarl
 *
 */
@SuppressWarnings("serial")
public class PaintPanel458 extends JPanel implements KeyListener {
	
	private static final int ROTATE_X = 10;
	private static final int ROTATE_Y = 11;
	private static final int ROTATE_Z = 12;

	private static final int NEG_ROTATE_X = 13;
	private static final int NEG_ROTATE_Y = 14;
	private static final int NEG_ROTATE_Z = 15;

	private static final double ROTATE_ANGLE = Math.PI/60;
	private static final int FRUSTUM = 1;
	private static final int ORTHO = 0;
	private static final double BOUNDRY_MOD = .1;

	private static RenderMatrix[] ROT_MATRICES =  {RenderMatrix.buildRotateX(ROTATE_ANGLE),
									  			   RenderMatrix.buildRotateY(ROTATE_ANGLE),
									  			   RenderMatrix.buildRotateZ(ROTATE_ANGLE),
									  			   RenderMatrix.buildRotateX(-ROTATE_ANGLE),
									  			   RenderMatrix.buildRotateY(-ROTATE_ANGLE),
									  			   RenderMatrix.buildRotateZ(-ROTATE_ANGLE)};
	
	private RenderMatrix FRUSTUM_MATRIX = RenderMatrix.buildTranslate(0, 0, 0);
	private RenderMatrix ORTHO_MATRIX = RenderMatrix.buildTranslate(0, 0, 0);
	private RenderMatrix CURRENT_PERSPECTIVE = RenderMatrix.buildTranslate(0, 0, 0);
	private RenderMatrix interactiveMatrix = RenderMatrix.buildTranslate(0, 0, 0);
	private RenderMatrix LOOK_AT = RenderMatrix.buildTranslate(0, 0, 0);
	private RenderMatrix LOOK_AT_BUF = RenderMatrix.buildTranslate(0, 0, 0);
	
	private int CURRENT_ID = ORTHO;
	
    int width;
    int height;
    int imageSize;
    int[] pixels;    
    int blue = 0;
    
    final ArrayList<UnitShape> shapes = new ArrayList<UnitShape>();
	
	private double left = 0;
	private double right = 0;
	private double top = 0;
	private double bottom = 0;
	private double near = 0;
	private double far = 0;
	private double[][] zBuffer;
	private boolean shift_pressed;
	
    PaintPanel458() {
        setFocusable(true);
        addKeyListener(this);       
        
        UIgetInputFile(shapes); // get the input 
        initializeZBuffer();
        
        setPreferredSize(new Dimension(width,height));   
    }
    
    void drawPixel(int x, int y, int r, int g, int b) {
        pixels[(height-y-1)*width*3+x*3] = r;
        pixels[(height-y-1)*width*3+x*3+1] = g;
        pixels[(height-y-1)*width*3+x*3+2] = b;                
    }
    
    /**
     * Checks the buffer at location x and y to verify z can be sent to the pixel buffer.
     * @param x the x coordinate in question
     * @param y the y coordinate in question
     * @param z The potential new z
     * @return true if the pixel can be printed.
     */
    public boolean checkZBuffer(final int x, final int y, final double z) {
		if (x < 0 || x > width - 1|| y < 0 || y > height - 1) return false; 
		////System.out.println("Current Z " + zBuffer[x][y] + "\nPotential Z is " + z);
		if (zBuffer[x][y] >= z) {
    		zBuffer[x][y] = z;
    		return true;
    	} else {
        	return false;
    	}
    }
    
    private void resetZBuffer() {
    	for (int i = 0; i < width; i++) {
    		for (int j = 0; j < height; j++) {
    			zBuffer[i][j] = Long
    					.MAX_VALUE;
    		}
    	}
    }
    
    private void initializeZBuffer() {
    	zBuffer = new double[width][height]; // initialize the z buffer
    	for (int i = 0; i < width; i++) {
    		for (int j = 0; j < height; j++) {
    			zBuffer[i][j] = Double.MAX_VALUE;
    		}
    	}
    }
    
    void createImage() {
    
        width = 512;
        height = 512;
        imageSize = width * height;
        pixels = new int[imageSize * 3];
        
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                drawPixel( x, y, x*255/width, y*255/height, blue);
            }
        }
        for (int d = 0; d < width; d++) {
            drawPixel( d, d, 255, 255, 255);
        }
    }
    
    public void paintComponent(Graphics g) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        WritableRaster raster = image.getRaster();
        
        long time = System.currentTimeMillis();
        //System.out.println("Start time: " + time);
        createImage_temp();
        long time2 = System.currentTimeMillis();
        //System.out.println("End time: " + time2);
        //System.out.println("Ellipsed time: " + (time2 - time));
        
        raster.setPixels(0, 0, width, height, pixels);        
        g.drawImage(image, 0, 0, null);
    }
    

    public void keyReleased(KeyEvent e){
    	switch (e.getKeyCode()) {
    	case KeyEvent.VK_SHIFT: shift_pressed = false; break;
    	}
    }

    public void keyPressed(KeyEvent e){
    	//System.out.println("keyPressed");
    	switch (e.getKeyCode()) {
    	/*case KeyEvent.VK_U: 
    		RenderMatrix temp = LOOK_AT;
    		LOOK_AT = LOOK_AT_BUF; 
    		LOOK_AT_BUF = temp; 
    		break;
    	case KeyEvent.VK_I: 
    		RenderMatrix backup = LOOK_AT;
    		LOOK_AT = LOOK_AT_BUF; 
    		LOOK_AT_BUF = backup;
    		break;*/
    	case KeyEvent.VK_P: 
    		CURRENT_ID = FRUSTUM;
    		CURRENT_PERSPECTIVE = FRUSTUM_MATRIX;   		
    		break;
    	case KeyEvent.VK_O: 
    		CURRENT_ID = ORTHO;
    		CURRENT_PERSPECTIVE = ORTHO_MATRIX;
    		break;
    	case KeyEvent.VK_SHIFT: shift_pressed = true; break;
    		
    	case KeyEvent.VK_L: 
    		// shift view area left boundary by +- 10% 
    		if (shift_pressed) {
    			left-= (left * BOUNDRY_MOD);
    		} else {
    			left+= (left * BOUNDRY_MOD);
    		}
    		FRUSTUM_MATRIX = RenderMatrix.buildFrustum(left, right, top, bottom, near, far);
    		ORTHO_MATRIX = RenderMatrix.buildOrtho(left, right, top, bottom, near, far);
			resetCurrentPerspective();
			break;
    	case KeyEvent.VK_R:
    		// shift view area right boundary by +- 10%
    		if (shift_pressed) {
    			right-=(right * BOUNDRY_MOD);
    		} else {
    			right+=(right * BOUNDRY_MOD);
    		}
    		FRUSTUM_MATRIX = RenderMatrix.buildFrustum(left, right, top, bottom, near, far);
    		ORTHO_MATRIX = RenderMatrix.buildOrtho(left, right, top, bottom, near, far);
			resetCurrentPerspective();
			break;
    	case KeyEvent.VK_T: 
    		// shift view area top boundary by +- 10%
    		if (shift_pressed) {
    			top-=(top * BOUNDRY_MOD);
    		} else {
    			top+=(top * BOUNDRY_MOD);
    		}
    		FRUSTUM_MATRIX = RenderMatrix.buildFrustum(left, right, top, bottom, near, far);
    		ORTHO_MATRIX = RenderMatrix.buildOrtho(left, right, top, bottom, near, far);
			resetCurrentPerspective();
			break;
			
    	case KeyEvent.VK_B: 
    		// shift view area bottom boundary by +- 10%
    		if (shift_pressed) {
    			bottom-=(bottom * BOUNDRY_MOD);
    		} else {
    			bottom+=(bottom * BOUNDRY_MOD);
    		}
    		FRUSTUM_MATRIX = RenderMatrix.buildFrustum(left, right, top, bottom, near, far);
    		ORTHO_MATRIX = RenderMatrix.buildOrtho(left, right, top, bottom, near, far);
			resetCurrentPerspective();
			break;

    	case KeyEvent.VK_N: 
    		// shift view area near boundary by +- 10%
    		if (shift_pressed) {
    			near-=(near * BOUNDRY_MOD);
    		} else {
    			near+=(near * BOUNDRY_MOD);
    		}
    		FRUSTUM_MATRIX = RenderMatrix.buildFrustum(left, right, top, bottom, near, far);
    		ORTHO_MATRIX = RenderMatrix.buildOrtho(left, right, top, bottom, near, far);
			resetCurrentPerspective();
    		break;

    	case KeyEvent.VK_V: 
    		// shift view area far boundary by +- 10%
    		if (shift_pressed) {
    			far-=(far * BOUNDRY_MOD);
    		} else {
    			far+=(far * BOUNDRY_MOD);
    		}
    		FRUSTUM_MATRIX = RenderMatrix.buildFrustum(left, right, top, bottom, near, far);
    		ORTHO_MATRIX = RenderMatrix.buildOrtho(left, right, top, bottom, near, far);
			resetCurrentPerspective();
			break;

    	
    	case KeyEvent.VK_UP: keyRotate(ROTATE_X); break;  // rotate -x
    	case KeyEvent.VK_DOWN: keyRotate(NEG_ROTATE_X); break; // rotate x
    		
    	case KeyEvent.VK_LEFT: keyRotate(ROTATE_Y); break; // rotate -y
    	case KeyEvent.VK_RIGHT: keyRotate(NEG_ROTATE_Y); break; // rotate y
    		
    	case KeyEvent.VK_A: keyRotate(ROTATE_Z); break; // rotate z
    	case KeyEvent.VK_S: keyRotate(NEG_ROTATE_Z); break; // rotate -z
        	// rotate y axis
        }        
        repaint();        
    }

    private void resetCurrentPerspective() {
    	switch(CURRENT_ID) {
		case ORTHO: CURRENT_PERSPECTIVE = ORTHO_MATRIX; break;
		case FRUSTUM: CURRENT_PERSPECTIVE = FRUSTUM_MATRIX; break;
		}
	}

	private void keyRotate(final int axis) {
		switch (axis) {
		case ROTATE_X: interactiveMatrix = ROT_MATRICES[0].multiply(interactiveMatrix); break;
		case ROTATE_Y: interactiveMatrix = ROT_MATRICES[1].multiply(interactiveMatrix); break;
		case ROTATE_Z: interactiveMatrix = ROT_MATRICES[2].multiply(interactiveMatrix); break;
		case NEG_ROTATE_X: interactiveMatrix = ROT_MATRICES[3].multiply(interactiveMatrix); break;
		case NEG_ROTATE_Y: interactiveMatrix = ROT_MATRICES[4].multiply(interactiveMatrix); break;
		case NEG_ROTATE_Z: interactiveMatrix = ROT_MATRICES[5].multiply(interactiveMatrix); break;
		default: return;
		}	
	}

	public void keyTyped(KeyEvent e) {
    }        

    public static void main(String args[]) {
        JFrame frame = new JFrame("Paint Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new PaintPanel458());
        frame.pack();      
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }

    void createImage_temp() {
        pixels = new int[width * height * 3];
        resetZBuffer();
        setBackgroundColor(Color.WHITE);
        // translate the vertices to shapes.
        RenderMatrix matrix = CURRENT_PERSPECTIVE.multiply(LOOK_AT);
        
        matrix = matrix.multiply(interactiveMatrix);
        for(int i = 0; i < shapes.size(); i++) {
        	shapes.get(i).getPoints(width, height, this, matrix);
        }
    }

	private void setBackgroundColor(Color white) {
    	for (int x = 0; x < width; x++) {
        	for (int y = 0; y < height; y++) {
        		drawPixel( x, y, 255, 255, 255);
        	}
        }
	}

	private boolean UIgetInputFile(final ArrayList<UnitShape> the_shapes) {
		try {
			processInputFile(the_shapes, JOptionPane.showInputDialog("Please Input a File Name"));
		} catch (FileNotFoundException e) {
			JOptionPane.showMessageDialog(null, "File Not Found. Goodbye");
			return false;
		} catch (NullPointerException npe) {
			JOptionPane.showMessageDialog(null, "Request Canceled. Goodbye");
			return false;
		} catch (InputMismatchException ime) {
			JOptionPane.showMessageDialog(null, "Invalid input structure. Goodbye");
			return false;
		} catch (NoSuchElementException nse) {
			JOptionPane.showMessageDialog(null, "Missing element. Goodbye");
			return false;
		}

		return true;        
	}
	/**
     * Processes the input file.
     * @param filename The txt file to process
     * @throws FileNotFoundException If file name is incorrect.
     * @throws NoSuchElementException If file is inproperly structured.
     * @throws InputMismatchException If input expected is not correct.
     */
    private boolean processInputFile(final ArrayList<UnitShape> UnitShapeList, final String filename) throws FileNotFoundException, NoSuchElementException, InputMismatchException {
    	Scanner scanline = new Scanner(new File(filename));
        
    	getDim(scanline);
    	
		RenderMatrix transMatrix = RenderMatrix.buildTranslate(0, 0, 0);
    	String token = null;
    	Color color = Color.WHITE;
    	
		while(scanline.hasNextLine()) {
			token = scanline.next();
			if (token.startsWith("WIRE")) {
				// //System.out.println(token);
				generateWireCube(color, transMatrix, shapes);
			} else if (token.startsWith("SOLID")) {
				// //System.out.println(token);
				generateSolidCube(color, transMatrix, shapes);
			} else if (token.equalsIgnoreCase("SCALE")) {
				// //System.out.println(token);
				transMatrix = transMatrix.multiply(RenderMatrix.buildScale(scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble()));
				//System.out.println("Matrix after Scale is applied\n" + transMatrix.toString());
			} else if (token.equalsIgnoreCase("TRANSLATE")) {
				// //System.out.println(token);
				transMatrix = RenderMatrix.buildTranslate(scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble()).multiply(transMatrix);
				//System.out.println("Matrix after translate is applied\n" + transMatrix.toString());
			} else if (token.startsWith("LOAD")) {
				transMatrix = RenderMatrix.buildTranslate(0, 0, 0);
			} else if (token.startsWith("ROTATE")) {
				// //System.out.println(token);
				transMatrix = addRotate(scanline, token, transMatrix);
				//System.out.println("Matrix after rotate is applied\n" + transMatrix.toString());
			} else if (token.equalsIgnoreCase("TRI")) {
				// construct a triangle from the next 3 scanline double tokens.
				UnitShapeList.add(generateTri(scanline, color, transMatrix));
			} else if (token.equalsIgnoreCase("LINE")){
				// construct a line from the next 2 scanline double tokens.
				UnitShapeList.add(generateLine(scanline, color, transMatrix));
			} else if (token.equalsIgnoreCase("RGB")) {
				color = new Color((int)(scanline.nextDouble() * 255), 
						          (int)(scanline.nextDouble() * 255), 
						          (int)(scanline.nextDouble() * 255));	
			} else if (token.equalsIgnoreCase("FRUSTUM")) {
				left = scanline.nextDouble();
				right = scanline.nextDouble();
				bottom = scanline.nextDouble();
				top = scanline.nextDouble();
				near = scanline.nextDouble();
				far = scanline.nextDouble();
				
				// projectionType = Matrix_4x4.FRUSTUM;
				setProjection(FRUSTUM, left, right, bottom, top, near, far);	
			} else if (token.equalsIgnoreCase("ORTHO")) {
				left = scanline.nextDouble();
				right = scanline.nextDouble();
				bottom = scanline.nextDouble();
				top = scanline.nextDouble();
				near = scanline.nextDouble();
				far = scanline.nextDouble();

				// projectionType = Matrix_4x4.ORTHO;
				setProjection(ORTHO, left, right, bottom, top, near, far);
			} else if (token.equalsIgnoreCase("LOOKAT")) {
				LOOK_AT = RenderMatrix.buildLookAt(scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble(),
				          						   scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble(),
				          						   scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble());

			} else {
				//System.out.println(token);
				throw new InputMismatchException();
			}

			try {
				scanline.nextLine();
			} catch (NoSuchElementException nse) {
				break;
			}
		}
		scanline.close();
		return true;
	}

	private void setProjection(final int prospective, final double left, final double right,
							   final double bottom, final double top, final double near, final double far) {
		CURRENT_ID = prospective;
		FRUSTUM_MATRIX = RenderMatrix.buildFrustum(left, right, top, bottom, near, far);
		ORTHO_MATRIX = RenderMatrix.buildOrtho(left, right, top, bottom, near, far);
		resetCurrentPerspective();
	}

	private ArrayList<UnitShape> generateSolidCube(final Color color, final RenderMatrix transMatrix, final ArrayList<UnitShape> shapes) {
		final double five = .5;
		// z plane
		shapes.add(new Tri(new double[]{-five, -five, five, 1}, new double[]{-five, five, five, 1}, 
				   new double[]{five, five, five, 1}, transMatrix, color));
		shapes.add(new Tri(new double[]{-five, -five, five, 1}, new double[]{five, -five, five, 1}, 
				   new double[]{five, five, five, 1}, transMatrix, color));

		// -x plane
		shapes.add(new Tri(new double[]{-five, -five, -five, 1}, new double[]{-five, five, -five, 1}, 
						   new double[]{-five, five, five, 1}, transMatrix, color));
		shapes.add(new Tri(new double[]{-five, -five, -five, 1}, new double[]{-five, -five, five, 1}, 
					   	   new double[]{-five, five, five, 1}, transMatrix, color));
		// -y plane
		shapes.add(new Tri(new double[]{-five, -five, -five, 1}, new double[]{five, -five, -five, 1}, 
						   new double[]{five, -five, five, 1}, transMatrix, color));
		shapes.add(new Tri(new double[]{-five, -five, -five, 1}, new double[]{-five, -five, five, 1}, 
				 		   new double[]{five, -five, five, 1}, transMatrix, color));		
		// -z plane
		shapes.add(new Tri(new double[]{-five, -five, -five, 1}, new double[]{five, -five, -five, 1}, 
						   new double[]{five, five, -five, 1}, transMatrix, color));
		shapes.add(new Tri(new double[]{-five, -five, -five, 1}, new double[]{-five, five, -five, 1}, 
						   new double[]{five, five, -five, 1}, transMatrix, color));
		// x plane
		shapes.add(new Tri(new double[]{five, -five, -five, 1}, new double[]{five, five, -five, 1}, 
						   new double[]{five, five, five, 1}, transMatrix, color));
		shapes.add(new Tri(new double[]{five, -five, -five, 1}, new double[]{five, -five, five, 1}, 
						   new double[]{five, five, five, 1}, transMatrix, color));
		// y plane
		shapes.add(new Tri(new double[]{-five, five, -five, 1}, new double[]{five, five, -five, 1}, 
						   new double[]{five, five, five, 1}, transMatrix, color));
		shapes.add(new Tri(new double[]{-five, five, -five, 1}, new double[]{-five, five, five, 1}, 
						   new double[]{five, five, five, 1}, transMatrix, color));
		
		return shapes;
	}

	private RenderMatrix addRotate(final Scanner scanline, final String token, final RenderMatrix transMatrix) {
		final double angle = Math.toRadians(scanline.nextDouble());
		switch(token.charAt(token.length() - 1)) {
		case 'X': 
			return RenderMatrix.buildRotateX(angle).multiply(transMatrix);
		case 'Y':
			return RenderMatrix.buildRotateY(angle).multiply(transMatrix); 
		case 'Z':
			return RenderMatrix.buildRotateZ(angle).multiply(transMatrix);
		default: new InputMismatchException();
		}
		return null;
	}

	private void generateWireCube(final Color color, final RenderMatrix transMatrix, final ArrayList<UnitShape> shapes) {
		shapes.add(new Line(new double[]{0.5, 0.5, 0.5, 1}, new double[]{0.5, 0.5, -0.5, 1}, transMatrix, color));
		shapes.add(new Line(new double[]{0.5, 0.5, 0.5, 1}, new double[]{0.5, -0.5, 0.5, 1}, transMatrix, color));
		shapes.add(new Line(new double[]{0.5, 0.5, 0.5, 1}, new double[]{-0.5, 0.5, 0.5, 1}, transMatrix, color));
		
		shapes.add(new Line(new double[]{-0.5, -0.5, 0.5, 1}, new double[]{0.5, -0.5, 0.5, 1}, transMatrix, color));
		shapes.add(new Line(new double[]{-0.5, -0.5, 0.5, 1}, new double[]{-0.5, 0.5, 0.5, 1}, transMatrix, color));
		shapes.add(new Line(new double[]{-0.5, -0.5, 0.5, 1}, new double[]{-0.5, -0.5, -0.5, 1}, transMatrix, color));
		
		shapes.add(new Line(new double[]{-0.5, 0.5, -0.5, 1}, new double[]{0.5, 0.5, -0.5, 1}, transMatrix, color));
		shapes.add(new Line(new double[]{-0.5, 0.5, -0.5, 1}, new double[]{-0.5, 0.5, 0.5, 1}, transMatrix, color));
		shapes.add(new Line(new double[]{-0.5, 0.5, -0.5, 1}, new double[]{-0.5, -0.5, -0.5, 1}, transMatrix, color));
		
		shapes.add(new Line(new double[]{0.5, -0.5, -0.5, 1}, new double[]{0.5, -0.5, 0.5, 1}, transMatrix, color));
		shapes.add(new Line(new double[]{0.5, -0.5, -0.5, 1}, new double[]{0.5, 0.5, -0.5, 1}, transMatrix, color));
		shapes.add(new Line(new double[]{0.5, -0.5, -0.5, 1}, new double[]{-0.5, -0.5, -0.5, 1}, transMatrix, color));
		
	}

	/**
	 * Collects the information from the input text and assigns values to the 
	 * the width and height.
	 * @param scanline The input file.
	 * @return true if successful in getting the width and height.
	 * If false the scanner object will not be refreshed to a new line.
	 * @throws InputMismatchException
	 */
	private boolean getDim(Scanner scanline) throws InputMismatchException {
		if (scanline.next().equalsIgnoreCase("dim")) {
			// get width.
			width = scanline.nextInt();
    		// get height.
       		height = scanline.nextInt();
		} else {
			return false;
		}
    	scanline.nextLine(); // clear to end of line.
    	return true;
	}

	/**
	 * Constructs a triangle from the scanline input
	 * @param scanline The input text.
	 * @param color The color of the Line.
	 * @param transMatrix 
	 * @return The line.
	 */
	private UnitShape generateLine(final Scanner scanline, final Color color, final RenderMatrix transMatrix) {
		//System.out.println("newLine");
		// get the points
		final double[] pointA = {scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble(), 1};
		final double[] pointB = {scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble(), 1};
		// create the line.
		final Line line = new Line(pointA, pointB, transMatrix, color);
		return line;
	}

	/**
	 * Constructs a triangle from the scanline input
	 * @param scanline The input text.
	 * @param color The color of the triangle
	 * @return The triangle.
	 */
	private UnitShape generateTri(final Scanner scanline, final Color color, final RenderMatrix transMatrix) {
		final double[] pointA = {scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble(), 1};
		final double[] pointB = {scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble(), 1};
		final double[] pointC = {scanline.nextDouble(), scanline.nextDouble(), scanline.nextDouble(), 1};
		
		final Tri tri = new Tri(pointA, pointB, pointC, transMatrix, color);
		return tri;
	}


}